# Quick Start

## Как работает KubeLatte?  

KubeLatte работает как динамический контроллер приема входящих соединений ([dynamic admission controller](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)) в кластере Kubernetes. Сервер Kubelatte позволяет гибко контролировать работу с ресурсами в кластре Kubernetes.

Kubelatte предполагает несколько режимов работы: валидатор, мутатор и креатор.

- валидатор обеспечивает корректность написания конфигураций ресурсов кластера;
- мутатор позволяет модифицировать любые ресурсы кластера при их публикации или изменении;
- креация – это процесс автоматической публикации объектов системы Kubernetes;
- sideEffect – процесс вызова создания ресурса из шаблона по мутационному хуку.

Политики KubeLatte соответствуют схеме ресурсов, используя структуру конкретного ресурса.
Важным преимуществом является возможность гибко настраивать сценарии мутации и валидации по множеству полей ресурсов Kubernetes, политики, конфигурирующие условия начала мутации или валидации, можно гибко и точно настраивать при помощи специального поля match.
Также состав API CRD Kubelatte включает в себя служебный ресурс TriggerInstance, запускающий создание ресурсов, при наличии в нем лейбла/аннотации, удовлетворяющими соответствующую политику вызова креации. 

Политики валидации позволяют разграничить ресурсы на группы, к которым применяются правила валидации при помощи секции match.
Правила позволяют нативно проверить значение любой секции.
Также базовый функционал валидации поддерживает язык rego.
Валидирующие правила используют особый синтаксис: сперва выполняется поиск по валидируемой конфигурации, после регулярное выражение конкретного правила маскирует результат поиска, в зависимости от результата поиска публикация ресурса может быть одобрена или отклонена.

На рисунке ниже показана высокоуровневая логическая архитектура KubeLatte.

![image arch](arch.png)

**Webhook** – это сервер, который обрабатывает входящие запросы AdmissionReview от сервера API Kubernetes и отправляет их на обработку в Mutation, Validation или Side Effect manager. Для обеспечения запросов на данный сервер необходимо настроить MutatingWebhookConfiguration/ValidatingWebhookConfiguration в рамках вашего кластера. После принятия запроса на мутацию/валидацию сервер может динамически настраиваться для более точной детерминации возможности мутации/валидации по вашим политикам Kubelatte (секция match в рамках Trigger/Scope соответственно). Далее webhook server направляет запрос на мутацию или валидацию в соответствующий manager. Также после проведения мутации возможно запустить шаблонизированную креацию. Webhook сервер передает информацию о мутируемом ресурсе в Side Effect manager. 

**Mutation Manager** обрабатывает пришедший ресурс, по надобности мутирует его, использую политики template и trigger. В политике типа Trigger указываются условия для начала мутации (секция match) и ссылки на соответвующие шаблоны для выполнения мутации. В самом шаблоне (тип Template) описываются мутируемые поля по схеме мутируемого ресурса.

**Validation Manager** проводит процесс валидации ресурсов из admission review по правилам, описанным в политике типа Scope, в случае нарушений, может отклонить создание ресурса.

Процесс создания ресурсов выделяется, так как **Creation Manager** следит за появлением ресурса типа TriggerInstance, и в случае, если в нем указан правильный лейбл или аннотация, описанные по аналогии с мутацией в ресурсе типа Trigger, то Creation Manager инициализирует запрос к API сервер Kubernetes по созданию подов описанных в шаблонах (тип Template), перечисленных в секции Trigger со ссылкой на реализуемую лейбл/аннотацию.

**Side Effect Manager** проводит фильтрацию запроса от webhook server посредством секции match (sideEffectConfigs в рамках Trigger) и в случае успеха фильтрации создается служебный ресурс TriggerInstance, вызывающий креацию, описанную выше.

Настройка MutatingWebhookConfiguration/ValidatingWebhookConfiguration и конфигураций Kubelatte позволяет использование как одного режима работы приложение, так и всех последовательно.

## Quick Start Guide

Этот раздел предназначен для предоставления вам кратких руководств по запуску и демонстрации нескольких ключевых функций KubeLatte.

Данные быстрые руководства, которые фокусируются на мутации, валидации и креации, позволяют познакомиться с основными функциями Kubelatte. Эти руководства предназначены только для демонстраций в лабораторных условиях или для демострации концепции.

1. Установите KubeLatte согласно краткому [руководству](Setup/install.md).

   ```shell
   KUBELATTE_NS=<имя проекта, где вы установили Kubelatte>
   NS=<ваш проект, может совпадать с KUBELATTE_NS>
   ```
   
2. Убедитесь, что ваш проект подключен к Kubelatte. Для этого в базовой конфигурации необходимо реализовать лейбл на проекте. Если вы дополнительно настраивали Mutating/Validating webhook configuration, то необходимо выполнить условия из данных конфигураций. 
   
   ```shell
   kubectl label namespace $NS kubealtte-injection=enabled
   ```

3. Выберите быстрое руководство, которое вас интересует:

- [Мутация](#мутация)
- [Креация](#креация)
- [Side Effect](#Side-Effect)
- [Валидация](#валидация)

(Альтернативно двигайтесь по инструкции сверху вниз)

_Let's start enjoy **Kube**rnetes as a cup of **latte**!_

### Мутация

Мутация – это возможность изменить, то есть "мутировать" любой ресурс каким-либо образом в момент его раскатки в кластере.  
Мутацию можно легко конфигурировать. Для описания конкретной мутации необходимо реализовать два ресурса API группы Kubelatte – **Template** и **Trigger**.

(Поля конфигураций аналогичны полям для .yaml-файлов Kubernetes)

#### kind: Template

Конфигурация Template предназначена для реализации «шаблона» с описанием изменяемой части для любого ресурса системы. К описанным полям в секции «data» данной конфигурации фактически будут применены изменения (эти изменения описаны в аннотации или метке label в конфигурации Trigger, описано ниже). Обращаем ваше внимание, что структура шаблона пода в секции «data» совпадает с фактической реализацией sidecar.

Добавьте данный шаблон мутации в свой кластер.

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Template
metadata:
  name: busybox-template
spec:
  apiVersion: v1
  kind: Pod
  data: |-
    spec:
      containers:
        - image: busybox
          command: ["/bin/sh"]
          args: ["-c", "while true; do echo 'Hi I am busybox sidecar. I was started at' $(date -u); sleep 5;done"]
          name: busybox
          resources: {}
EOF
```

Подробнее о Template можно найти [здесь](Mutation/template.md).

#### kind: Trigger

Конфигурация предназначена для фильтра входящих запросов на мутацию, необходимой для инициализации мутации. Также в данной конфигурации описывается список контейнеров/аннотаций/томов (для их мутации в пользовательском ресурсе).

Теперь следует реализовать правила, по которым будет вызываться инжектирование описанного ранее sidecar.

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Trigger
metadata:
  name: busybox-injection-trigger
spec:
  mutationConfigs:
    - name: busybox-injection
      match:
        kinds:
          - apiGroups:
              - ''
            kinds:
              - Pod
        name:
          value: nginx
        annotationSelector:
          matchExpressions:
            - key: busybox-injection
              operator: In
              values:
                - enabled
        operations:
          - CREATE
      updateStrategy: merge
      templateRefs:
        - $KUBELATTE_NS/busybox-template
EOF
```

В данном примере мы видим, что собираемся мутировать Pod с именем nginx, на котором реализована аннотация, описанная в селекторе в рамках секции match. Также указывается ссылка на опубликованный ранее template (ссылка реализована в виде <NAMESPACE>/<NAME OF TEMPALTE>).

Подробнее о Trigger можно найти [здесь](Mutation/trigger.md).

#### Теперь все готово для мутации!

Реализуем под nginx с данной аннотацией:

```shell
kubectl run nginx --image nginx --annotations kblt.io/busybox-injection=enabled -n $NS
```

Запросив логи, убеждаемся что нужный нам сайдкар опубликован в рамках пода.

```shell
kubectl logs nginx -c busybox --tail=5 -n $KUBELATTE_NS
```

Сравним два пода: опубликованный с аннотацией для мутации

Под без мутации:

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    run: nginx
spec:
  containers:
    - name: nginx
      image: nginx
      resources: {}
      imagePullPolicy: Always
  restartPolicy: Always
  terminationGracePeriodSeconds: 30
  dnsPolicy: ClusterFirst
  serviceAccountName: default
  serviceAccount: default
```

Под после мутации по политикам опубликованным ранее:

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    run: nginx
  annotations:
    busybox-injection: enabled
    kblt.mutation.resource: 'true'
spec:
  containers:
    - name: nginx
      image: nginx
      resources: {}
      imagePullPolicy: Always
    - name: busybox
      image: busybox
      command:
        - /bin/sh
      args:
        - '-c'
        - >-
          while true; do echo 'Hi I am busybox sidecar. I was created at' $(date -u);
          sleep 5;done
      resources: {}
      imagePullPolicy: Always
  restartPolicy: Always
  terminationGracePeriodSeconds: 30
  dnsPolicy: ClusterFirst
  serviceAccountName: default
  serviceAccount: default
```

Затем удалим под nginx:

```shell
kubectl delete pod nginx -n $NS
```

Так же мутация имеет следующий функционал:

- использование goTemplate для динамического рендеринга шаблона (полезно для распространения единых политик безопасности `Pod/spec.containers[].securityContext` в любой контейнер);
- подстановка custom значений для рендеринга мутации (кейс настройки сайдкара через аннотации);
- полная замена части мутируемых ресурсов (автозамена устаревшего сайдкара на более новый);
- гибкая настройка и разбивка ресурсы на группы и применимость шаблона к каждой из групп (секция match).

Подробнее о мутации можно прочитать [здесь](Mutation/Description.md).

### Креация

Креация – это создание произвольного ресурса в кластере. Главное отличие от мутационных triggers является наличие поля creationConfigs. А в шаблоне (template) полностью описан создаваемы ресурс. 

Опубликуем шаблон. В шаблоне описывается ресурс, который будет создан.

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Template
metadata:
  name: template-creation
spec:
  apiVersion: v1
  kind: Pod
  data: |-
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: nginx
      annotations:
        busybox-injection: enabled
    spec:
      containers:
        - name: nginx
          image: nginx
          imagePullPolicy: Always
EOF
```

Теперь необходимо реализовать связку между шаблоном и вызовом креации. Опубликуем trigger. Особенностью является поле `spec.creationConfigs[]`.

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Trigger
metadata:
  name: trigger-creation
spec:
  creationConfigs:
    - name: creation-via-label
      templateRefs:
        - $KUBELATTE_NS/template-creation
      labelSelector:
        matchExpressions:
          - key: kubelatte
            operator: In
            values:
              - creation-label
    - annotationNamespace: kubelatte
      annotationTrigger: via-annot
      name: creation-via-annotation
      templateRefs:
        - $KUBELATTE_NS/template-creation
EOF
```

Для данного туториала реализовано две связки, одна по аннотации, другая по лейблу, находящимся в служебной конфигурации TriggerInstance, для вызова креации мы публикуем по одной из них.

После публикации данного ресурса, на вашем проекте будет создан Pod по аннотации из TriggerInstance.

```shell
kubectl create -n $NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: TriggerInstance
metadata:
  annotations:
    kubelatte/via-annot: enabled
  name: annotation
EOF
```

Чтобы реализовать креацию по лейблу,необходимо создать TriggerInstance с лейблом из Trigger.

```shell
kubectl create -n $NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: TriggerInstance
metadata:
  labels:
    kubelatte: creation-label
  name: annotation
EOF
```

Удалив, TriggerInstance со своего проекта, вы автоматически вызовите удаление дочерних ресурсов (в нашем случае Pod nginx).

Так же креация имеет следующий функционал:

- подстановка параметров креации из `spec.data` TriggerInstance для использования GoTemplates в рамках Template;
- настройка имени создаваемого ресурса, добавление уникального хеша;
- отслеживания статуса дочерних ресурсов через статус TriggerInstance.

Подробнее о креации можно прочитать [здесь](Creation/Description.md).

### Валидация

Валидация – это проверка ресурса на корректность. Для того, чтобы предостеречься от публикации «плохих» объектов, есть возможность заранее написать правила, которые ограничивают публикацию объектов. Тем самым обеспечивается надежность и безопасность всего кластера, контроль за соблюдением этих политик.

Конфигурация «kind: Scope» предназначена для описания правил-ограничений на публикацию объектов.

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Scope
metadata:
  name: validation-pod
spec:
  type: validation
  items:
    - name: kubelatte-validation-pod
      match:
        kinds:
          - apiGroups:
              - '*'
            kinds:
              - Pod
        operations:
          - CREATE
      rule:
        simples:
          - name: validation-pod
            path: spec.restartPolicy
            value: Never
            action: deny
            message: 'restartPolicy must not be "Never"'
EOF
```

В данном примере конфигурация запрещает создание «kind: Pod», если значение секции spec.restartPolicy будет равно «Never». То есть, если пользователь захочет опубликовать Pod ниже, то он получит сообщение «restartPolicy must not be "Never"»

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Pod
metadata:
  name: validation-pod
spec:
  containers:
        - image: busybox
          command: ["/bin/sh"]
          args: ["-c", "while true; do echo 'Hi I am busybox. I was started at' $(date -u); sleep 5;done"]
          name: busybox
          resources: {}
  restartPolicy: Never
EOF
```

В конфигурации «kind: Template» описывается шаблон ресурса, который будет валидироваться. Для примера выше будет такой

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Template
metadata:
  name: validator-template
spec:
  apiVersion: kubelatte.io/v1alpha1
  kind: Pod
  data: |-
    metadata:
      name: validation-pod
      namespace: some_namespace
    spec:
      containers:
        - image: busybox
          command: ["/bin/sh"]
          args: ["-c", "while true; do echo 'Hi I am busybox. I was started at' $(date -u); sleep 5;done"]
          name: busybox
          resources: {}
      restartPolicy: Never
EOF
```

### Side Effect

Cоздание ресурса по публикации другого ресурса.

Ниже приведена вся цепочка конфигураций для автоматического создания Ingress после публикации Route.

Давайте реализуем SideEffect trigger для установки условий, при которых начинается процесс создания SideEffect ресурса.

Trigger для обработки мутационных запросов на необходимость производить SideEffect:

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Trigger
metadata:
  name: migration-ingress
spec:
  sideEffectConfigs: # отдельная секция для обработки запросов на мутацию для проверки необходимости производить SideEffect
    - match: # стандартная секция match для отбора запросов на мутацию и произведению по ним операции создания triggerInstance
        kinds:
          - apiGroups:
              - 'route.openshift.io'
            kinds:
              - Route
        operations:
          - CREATE
      name: creation-ti-ingress
      templateRefs:
        - kubelatte/creation-ti-ingress # ссылка на шаблон, в рамках которого описан создаваемый TriggerInstance
EOF
```

Далее необходимо сформировать шаблон по которому приложение будет понимать какой TriggerInstance нужно создать чтобы вызвать обычный процесс креации.

Шаблон для создания TriggerInstance:

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Template
metadata:
  name: creation-ti-ingress
spec:
  apiVersion: kubelatte.io/v1alpha1
  kind: TriggerInstance
  data: |-
    metadata:
      annotations: 
        kblt/creation-ingress: enabled
    spec:
      data: data # !!!ВАЖНО!!! оставить это поле
                 # ресурс по которомы был вызван SideEffect будет помещен в секцию data,
                 # чтобы потом можно было использовать параметризируемое в рамках triggerInstance создание нового ресурса
EOF
```

После инициализации SideEffect, будет создан служебный TriggerInstance по шаблону выше. Внимание! В рамках шаблона выше может находится только лишь описание создаваемого TriggerInstance, иные ресурсы описывать нельзя.

Пример ресурса Trigger, необходимый для захвата создаваемого TriggerInstance и проведения креации:

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Trigger
metadata:
  name: creation-ingress
spec:
  creationConfigs:
    - annotationNamespace: kblt
      annotationTrigger: creation-ingress
      name: creation-ingress
      disableUniqueName: 'true' # новый параметр, убирающий добавление хеш в имя создаваемого ресурса
      templateRefs:
        - kubelatte/creation-ingress
EOF
```

Параметризованный шаблон для креации Ingress:

```shell
kubectl create -n $KUBELATTE_NS -f - << EOF
apiVersion: kubelatte.io/v1alpha1
kind: Template
metadata:
  name: creation-ingress
spec:
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  data: |-
    metadata:
      name: sideeffect-{{% .Spec.DataObj.metadata.name %}} # если не указано имя будет эквивалентно имени ресурса-родителя, который вызвал SideEffect
      annotations:
        nginx.ingress.kubernetes.io/default-backend: "{{% .Spec.DataObj.spec.to.name %}}"
        nginx.ingress.kubernetes.io/secure-backends: 'true'
        nginx.ingress.kubernetes.io/ssl-passthrough: 'true'
        nginx.ingress.kubernetes.io/backend-protocol: HTTPS
    spec:
      ingressClassName: nginx
      rules:
        - host: "{{% .Spec.DataObj.spec.host %}}"
          http:
            paths:
              - path: "/"
                pathType: Prefix
                backend:
                  service:
                    name: "{{% .Spec.DataObj.spec.to.name %}}"
                    port:
                      name: "{{% .Spec.DataObj.spec.port.targetPort %}}"
EOF
```

Теперь можете попробовать опубликовать Route, на своем проекте и проверить создан ли Ingress.